﻿#include "device_state.hpp"

#include "db/sqlite_conn.hpp"
#include "app.hpp"

#include "wlog.hpp"
#include <regex>
#include <map>
#include "utils/utils_string.hpp"

#include <regex>


namespace bz
{
	void device_state::reg_obs(device_state_observer* ob)
	{
		obs_list_.insert(ob);
	}
	void device_state::unreg_obs(device_state_observer* ob)
	{
		obs_list_.erase(ob);
	}

	device* device_state::get_device(int id) {

		std::shared_lock<std::shared_mutex> lock(mutex_);
		auto it = device_map_.find(id);
		if (it != device_map_.end()) {
			return &device_map_[id];
		}
		else {
			return nullptr;
		}
	}

	void device_state::update_device()
	{
		/*auto db = sqlite_conn::get_conn();
		if (!db) return;
		sqlite_guard guard(db);
        device_list_ = db->query<device>();*/
		has_change_ = true;
	}

	device_state::device_state()
		:ios_(),
		work_(ios_),
		has_change_(true)
	{
		start_check();
	}

	device_state::~device_state()
	{
	
	}


	bool device_state::check_state()
	{
		
		if (has_change_) {
			has_change_ = false;
			auto db = sqlite_conn::get_conn();
			if (db) {
				sqlite_guard guard(db);
				device_list_ = db->query<device>();
			}
		}

		struct in_addr s;
		for (auto &row: device_list_)
		{
			row.online_state = false;
			
#ifdef __ANDROID__
				continue;
#endif // __ANDROID__
				string ip = row.ip;
				std::regex ipRegex(R"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))");

				std::smatch match;
				string ip_str;
				if (std::regex_search(ip, match, ipRegex)) {
					ip_str = match.str();
				}
				else {
					continue;
				}

				if (ip_str.empty()) {
					continue;
				}
				
				if (app::instance()->local_ip_set_.count(ip_str)) {
					row.online_state = 1;
				}
				else {
					auto res = ping_map_.find(ip_str);
					if (res == ping_map_.end())
					{
						shared_ptr<pinger> piner = make_shared<pinger>(ios_, ip_str.c_str());
						ping_map_.emplace(ip_str, piner);
					}
					else
					{
						row.online_state = res->second->state_;
					}
				}
			
			
		}



		/*auto item = ping_map_.begin();

		while (item != ping_map_.end())
		{
			bool has = false;

			for (auto row : device_list_)
			{
				
					
				string ip_str = row.ip;
				std::regex ipRegex("\\b(?:\\d{1,3}\\.){3}\\d{1,3}\\b");
				std::smatch match;

				if (std::regex_search(ip_str, match, ipRegex)) {
					ip_str = match.str();
				}

				if (item->first == ip_str) {
					has = true;
					//row.online_state = item->second->state_;
				}
				
			}

			if (!has) 
			{
				ping_map_.erase(item++);
			}
			else 
			{
				item++;
			}
		}*/

		std::unique_lock<std::shared_mutex> lock(mutex_);
		for (auto it: device_list_)
		{
			device_map_[it.id]=it;
		}
		
		for (auto ob: obs_list_)
		{
			ob->on_state_change();
		}
		return true;

	}

	void device_state::start_check()
	{
        update_device();
        check_timer_ = app::instance()->timer_->AddTimer(10s, &device_state::check_state, this);

        thread_ = std::thread([this]()
            {
                boost::system::error_code ec;
                ios_.run(ec);
            });

	}
}
